package com.bc.web.controller.admin;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.fs.common.extend.FSController;
import com.fs.common.util.FSDate;
import com.fs.common.util.FSIDGenerate;
import com.bc.web.config.SystemConfig;
import com.bc.web.config.SystemEnum;
import com.bc.web.model.Channel;
import com.bc.web.model.ChannelFee;
import com.bc.web.model.ClearingDetail;
import com.bc.web.model.ClearingMonitor;
import com.bc.web.model.TradeOrder;
import com.bc.web.service.CalcFeeService;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Page;

public class ClearingMonitorController extends FSController {
	private int BATCH_NUMBER = 2000;
	private final String hicard_that_amt = SystemConfig.config.get("hicard_that_amt"); //金额手续费低价判断

	public void search() {
		Page<ClearingMonitor> pageResult = ClearingMonitor.dao.search(super.getSearchCondition());
		List<Channel> channelList = Channel.dao.selectAll();
		setPageResultToRequest("items", pageResult);
		setAttr("channelList", channelList);
		render("clearing/monitor/monitorList.html");
	}

	public void createMonitor() {
		String settleDate = getPara("settleDate");
		String now = FSDate.getDate();
		if (StrKit.isBlank(settleDate)) {
			renderFail("日切日期必填！", false);
			return;
		}
		if (now.compareTo(settleDate) <= 0) {
			renderFail("监听数据必须小于当天！", false);
			return;
		}
		List<ClearingMonitor> monitorList = ClearingMonitor.dao.find("select * from clearing_monitor where settleDate=?", settleDate);
		if (monitorList.isEmpty()) {
			// TODO 暂时无法获取渠道数据，就不生成各个渠道的记录
			/*List<Channel> channelList = Channel.dao.selectAll();
			Channel local = new Channel();
			local.setCode(SystemEnum.ChannelCode.Local.getValue());
			channelList.add(local);
			for (int i = 0; i < channelList.size(); i++) {
				ClearingMonitor m = new ClearingMonitor();
				m.setChannelCode(channelList.get(i).getCode());
				m.setSettleDate(settleDate);
				m.setProcessStatus(SystemEnum.ProcessStatus.Init.getValue());
				m.setSumAmount(0L);
				m.setSuccessAmount(0L);
				ClearingMonitor c = ClearingMonitor.dao.select(m.getChannelCode(), settleDate);
				if (c == null) {
					m.save();
				} 
			}*/
			
			ClearingMonitor m = new ClearingMonitor();
			m.setChannelCode(SystemEnum.ChannelCode.Local.getValue());
			m.setSettleDate(settleDate);
			m.setProcessStatus(SystemEnum.ProcessStatus.Init.getValue());
			m.setSumAmount(0L);
			m.setSuccessAmount(0L);
			ClearingMonitor c = ClearingMonitor.dao.select(m.getChannelCode(), settleDate);
			if (c == null) {
				m.save();
			} 
			
			renderSuccess(false);
		} else {
			renderFail("该日期监听数据已经生成！", false);
		}
	}

	/**
	 * 取数，并在取渠道数据时进行对账操作
	 */
	public void getData() {
		ClearingMonitor monitor = ClearingMonitor.dao.findById(getPara("id"));
		String channelCode = monitor.getChannelCode();
		// 监听数据的渠道是号是本地只取本地数据
		if (SystemEnum.ChannelCode.Local.getValue().equals(channelCode)) {
			this.getLocalData(monitor);
			renderSuccess(false);
			return;
		} 
		
		// 本地数据导入成功了再获取渠道数据
		ClearingMonitor localMonitor = ClearingMonitor.dao.select(SystemEnum.ChannelCode.Local.getValue(), monitor.getSettleDate());
		if (localMonitor == null || SystemEnum.ProcessStatus.GetDataSuccess.getValue().equals(localMonitor.getProcessStatus()) == false) {
			this.getLocalData(localMonitor);
		}
		
		// 获取渠道数据
		List<ClearingDetail> channelDetailList = this.getChannelData(monitor.getChannelCode());
		if (channelDetailList == null || channelDetailList.isEmpty()) {
			renderFail(false);
			return;
		}
		
		// 对账
		this.compare(monitor, channelDetailList); 
		renderSuccess(false);
	}
	
	/**
	 * 获取本地数据
	 * 
	 * @param monitor
	 */
	private void getLocalData(ClearingMonitor monitor) {
		List<TradeOrder> orderList = TradeOrder.dao.selectClearingData(monitor.getSettleDate());
		List<ClearingDetail> detailList = new ArrayList<>();
		long sumAmount = 0L;
		for (int i = 0; i < orderList.size(); i++) {
			TradeOrder v = orderList.get(i);
			int channelFee = 0;
			ChannelFee channelFeeInfo = ChannelFee.dao.selectChannelFee(v.getChannelCode(), v.getPayType());
			if (channelFeeInfo != null) {
				CalcFeeService calc = new CalcFeeService();
				channelFee = calc.getFee(v.getAmount(), channelFeeInfo.getFeeId());
			}
			if(v.getChannelCode().equals("hicardpay") && v.getAmount() <= Integer.parseInt(hicard_that_amt)) {
				channelFee = 100;
			}
			ClearingDetail d = new ClearingDetail();
			d.setId(v.getId());
			d.setChannelCode(v.getChannelCode());
			d.setOrgCode(v.getOrgCode());
			d.setMerchCode(v.getMerchCode());
			d.setOrderNo(v.getOrderNo());
			d.setOriginalOrderNo(v.getOriginalOrderNo());
			d.setMerchOrderNo(v.getMerchOrderNo());
			d.setPayTypeCode(v.getPayType());
			d.setAmount(Math.abs(v.getAmount()));
			d.setFee(Math.abs(v.getMerchFee()));
			d.setChannelFee(channelFee);
			d.setPayTime(v.getPayTime());
			d.setSettleDate(monitor.getSettleDate());
			d.setCompareStatus(SystemEnum.CompareStatus.Init.getValue());
			d.setPaymentStatus(SystemEnum.PaymentStatus.Init.getValue());
			d.setIsRisk(false);
			d.setDataType(SystemEnum.DataType.Local.getValue());
			sumAmount = sumAmount + d.getAmount();
			detailList.add(d);
		}
		if (detailList.size() > 0) {
			Db.batchSave(detailList, BATCH_NUMBER);
			monitor.setProcessStatus(SystemEnum.ProcessStatus.GetDataSuccess.getValue());
			monitor.setDataCount(detailList.size());
			monitor.setSumAmount(sumAmount);
			monitor.update();
		}
	}
	
	/**
	 * 获取渠道数据
	 * 
	 * @param channelCode
	 * @return
	 */
	private List<ClearingDetail> getChannelData(String channelCode) {
		switch(channelCode) {
			case "Channel1": return null;
			case "Channel2": return null;
			default: return null;
		}
	}
	
	/**
	 * 对账处理
	 * 
	 * @param monitor
	 * @param channelDetailList
	 */
	private void compare(ClearingMonitor monitor, List<ClearingDetail> channelDetailList) {
		List<ClearingDetail> localDetailList = ClearingDetail.dao.select(monitor.getChannelCode(), monitor.getSettleDate(), SystemEnum.DataType.Local.getValue());
		Map<String, ClearingDetail> localMap = new HashMap<String, ClearingDetail>();
		for (int i = 0; i < localDetailList.size(); i++) {
			ClearingDetail detail = localDetailList.get(i);
			localMap.put(detail.getOrderNo(), detail);
		}

		// 对账处理
		List<ClearingDetail> success = new ArrayList<>();
		List<ClearingDetail> localError = new ArrayList<>();
		List<ClearingDetail> channelError = new ArrayList<>();
		long successAmount = 0L;
		long localErrorAmount = 0L;
		long channelErrorAmount = 0L;
		for (int i = 0; i < channelDetailList.size(); i++) {
			ClearingDetail channelDetail = channelDetailList.get(i);
			ClearingDetail localDetail = localMap.get(channelDetail.getOrderNo());
			if (localDetail != null) {
				localDetail.setChannelFee(channelDetail.getChannelFee());
				localDetail.setCompareStatus(SystemEnum.CompareStatus.Success.getValue());
				success.add(localDetail);
				successAmount = successAmount + channelDetail.getAmount();
				localMap.remove(localDetail.getOrderNo());
			} else {
				// 渠道差错
				channelDetail.setId(FSIDGenerate.getUUID());
				channelDetail.setCompareStatus(SystemEnum.CompareStatus.ChannelError.getValue());
				channelDetail.setPaymentStatus(SystemEnum.PaymentStatus.Init.getValue());
				channelDetail.setIsRisk(false);
				channelDetail.setDataType(SystemEnum.DataType.Channel.getValue());
				channelErrorAmount = channelErrorAmount + channelDetail.getAmount();
				channelError.add(channelDetail);
			}
		}

		// 本地差错
		if (localMap.size() > 0) {
			for (Map.Entry<String, ClearingDetail> entry : localMap.entrySet()) {
				ClearingDetail d = entry.getValue();
				d.setCompareStatus(SystemEnum.CompareStatus.LocalError.getValue());
				localErrorAmount = localErrorAmount + d.getAmount();
				localError.add(d);
			}
		}

		if (success.size() > 0) {
			Db.batchUpdate(success, BATCH_NUMBER);
		}
		if (localError.size() > 0) {
			Db.batchUpdate(localError, BATCH_NUMBER);
		}
		if (channelError.size() > 0) {
			Db.batchSave(channelError, BATCH_NUMBER);
		}
		monitor.setDataCount(channelDetailList.size());
		monitor.setSumAmount(successAmount + channelErrorAmount);
		monitor.setSuccessCount(success.size());
		monitor.setSuccessAmount(successAmount);
		monitor.setLocalErrorCount(localError.size());
		monitor.setLocalErrorAmount(localErrorAmount);
		monitor.setChannelErrorCount(channelError.size());
		monitor.setChannelErrorAmount(channelErrorAmount);
		monitor.setProcessStatus(SystemEnum.ProcessStatus.CompareSuccess.getValue());
		monitor.update();
	}

}
